package moodish.dummy;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import moodish.comm.ClientMessage;
import moodish.comm.ServerComm;
import moodish.comm.ServerMessage;
import moodish.comm.ServerSideMessage;
import moodish.comm.ClientSideMessage.Type;

/**
 * The Class ServerCommDummy.
 */
public class ServerCommDummy implements ServerComm {

	/** The Constant PORT for the clients to know which port to connect */
	public static final int PORT = 8080;
	
	/** The receive message list. */
	private BlockingQueue<ServerMessage> receiveMessageList;
	
	/** The client map. */
	private HashMap<String, DealWithClient> clientMap;

	/**
	 * Method which starts the MoodishServer as well as thread to listen for connections.
	 * The anonymous thread run() creates a DealWithClient object for each client that tries to connect. 
	 * 
	 * @see moodish.comm.ServerComm#start()
	 * 
	 */
	@Override
	public void start() {
		receiveMessageList = new LinkedBlockingQueue<ServerMessage>();
		clientMap = new HashMap<String, DealWithClient>();
		new Thread() {
			@Override
			public void run() {
				try {
					ServerSocket serverSocket = new ServerSocket(PORT);
					while (true) {
						new DealWithClient(serverSocket.accept(), getThis());
					}
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}.start();
		;

	}
	

	/**
	 * @return true if the receiveMessageList has messages 
	 * 
	 * @see moodish.comm.ServerComm#hasNextMessage()
	 */
	@Override
	
	public boolean hasNextMessage() {
		return !receiveMessageList.isEmpty();
	}

	/**
	 * @return the next ServerSideMessage in the receiverMessageList
	 * 
	 * @see moodish.comm.ServerComm#getNextMessage()
	 */
	@Override
	public ServerSideMessage getNextMessage() {
		ServerMessage sm = null;
		try {
			sm = receiveMessageList.take();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return sm;
	}

	/**
	 * Method to be used by the server to send a message to a client that has been invited to a friendship
	 * 
	 * @see moodish.comm.ServerComm#sendNewFriendship(java.lang.String, java.lang.String)
	 */
	@Override
	public void sendNewFriendship(String toNickname, String newFriendship) {
		ClientMessage cm = new ClientMessage(toNickname, newFriendship,
				Type.FRIENDSHIP);
		getClientMap().get(toNickname).getSendMessageList().add(cm);
	}

	/**
	 * Method to be used by the server to send a message error to a client 
	 * 
	 * @see moodish.comm.ServerComm#sendError(java.lang.String, java.lang.String)
	 */
	@Override
	public void sendError(String toNickname, String error) {
		ClientMessage cm = new ClientMessage(toNickname, error, Type.ERROR);
		getClientMap().get(toNickname).getSendMessageList().add(cm);
	}

	/**
	 * @param nickname of the client
	 * @return true if a client is connected
	 * 
	 * @see moodish.comm.ServerComm#clientIsConnected(java.lang.String)
	 */
	@Override
	public boolean clientIsConnected(String nickname) {
		return getClientMap().containsKey(nickname);
	}

	/**
	 * Method to be used by the server to send a message to a client informing that a user has connected.
	 * 
	 * @see moodish.comm.ServerComm#sendClientConnected(java.lang.String, java.lang.String)
	 */
	@Override
	public void sendClientConnected(String toNickname, String userConnected) {
		ClientMessage cm = new ClientMessage(toNickname, userConnected,
				Type.CONNECTED);
		getClientMap().get(toNickname).getSendMessageList().add(cm);
	}

	/**
	 * Method to be used by the server to send a message to a client informing that a user has disconnected
	 * 
	 * @see moodish.comm.ServerComm#sendClientDisconnected(java.lang.String, java.lang.String)
	 */
	@Override
	public void sendClientDisconnected(String toNickname,
			String userDisconnected) {
		ClientMessage cm = new ClientMessage(toNickname, userDisconnected,
				Type.DISCONNECTED);
		getClientMap().get(toNickname).getSendMessageList().add(cm);

	}

	/**
	 * Method to be used by the server to disconnect a client
	 * 
	 * @see moodish.comm.ServerComm#disconnectClient(java.lang.String)
	 */
	@Override
	public void disconnectClient(String nickname) {
		getClientMap().remove(nickname);
	}

	/**
	 * 
	 * Method to be used by the server to send a moodish message to a client 
	 * 
	 * @see moodish.comm.ServerComm#sendMoodishMessage(java.lang.String, java.lang.String, java.lang.String)
	 */
	@Override
	public void sendMoodishMessage(String fromNickname, String toNickname,
			String message) {
		ClientMessage cm = new ClientMessage(fromNickname, message,
				Type.MOODISH_MESSAGE);
		getClientMap().get(toNickname).getSendMessageList().add(cm);
	}

	/**
	 * Method to be used by the server to send a message to a client that has been removed from a friendship
	 * 
	 * @see moodish.comm.ServerComm#sendNewUnfriendship(java.lang.String, java.lang.String)
	 */
	@Override
	public void sendNewUnfriendship(String toNickname, String newFriendship) {
		ClientMessage cm = new ClientMessage(toNickname, newFriendship,
				Type.UNFRIENDSHIP);
		getClientMap().get(toNickname).getSendMessageList().add(cm);
	}

	/**
	 * Gets the receive message list.
	 *
	 * @return the receive message list
	 */
	public BlockingQueue<ServerMessage> getReceiveMessageList() {
		return receiveMessageList;
	}

	/**
	 * Gets the client map.
	 *
	 * @return the client map
	 */
	public HashMap<String, DealWithClient> getClientMap() {
		return clientMap;
	}

	/**
	 * Gets the instance of the class.
	 *
	 * @return this
	 */
	private ServerCommDummy getThis() {
		return this;
	}
}
